package com.ruoyi.apm.http.client;

import java.util.*;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.util.StringUtil;
import com.ruoyi.apm.dao.DockDataConfigMapper;
import com.ruoyi.apm.dao.DockDataMapper;
import com.ruoyi.apm.model.*;
import com.ruoyi.apm.service.DockDataService;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import org.apache.http.client.CookieStore;
import org.apache.http.impl.client.BasicCookieStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.stereotype.Component;

public class HttpSequenceHandle {

	protected static final Logger LOGGER = LoggerFactory.getLogger(HttpClientHandler.class);


	private HttpSequence httpSequence;

	public HashMap<String,String> variables = new HashMap<String,String>();
	
	public ArrayList<HttpRequestLog> httpRequestLogList = new ArrayList<HttpRequestLog>();
	
	public HttpSequenceLog httpSequenceLog;
	
	public HttpSequenceHandle(HttpSequence httpSequence) {
		this.httpSequence = httpSequence;
	}
	//cookie保存
	CookieStore cookieStore=new BasicCookieStore();


	public void execute(){
		httpSequenceLog = new HttpSequenceLog();
		httpSequenceLog.setCostTime(new Date().getTime());
		DockDataConfig dockDataConfig = SpringUtils.getBean(DockDataConfigMapper.class).getByGuid(httpSequence.getGuid());
		StringBuffer insertError = new StringBuffer();
		try {
			if(HttpSequence.JobType.DOCKDATA.name().equals(httpSequence.getJobType())){
				if(dockDataConfig.getDataSource().equals(DataSourceType.CK.name())){
					SpringUtils.getBean(DockDataService.class).insertDataForCk(httpSequence,this,dockDataConfig.getDataSource());
				}else{
					SpringUtils.getBean(DockDataService.class).insertDataForMysql(httpSequence,this,dockDataConfig.getDataSource());
				}
			}else if(HttpSequence.JobType.MONITOR.name().equals(httpSequence.getJobType())){
				excuteMonitor();
			}
		} catch (Exception e) {
			e.printStackTrace();
			StackTraceElement[] stackTraceElements = e.getStackTrace();
			for(StackTraceElement element:stackTraceElements){
				if(insertError.length()!=0){
					insertError.append("\r\n");
				}
				insertError.append(element.toString());
			}
		}
		handleLog(insertError);
	}

	/**
	 *
	 * @param list
	 * @param request
	 * @param dockDataConfig
	 * @param apiData 是否是获取数据的接口调用
	 * @return
	 */
	public boolean excuteOne(List<Map<String,Object>> list,HttpRequest request,DockDataConfig dockDataConfig,boolean apiData,boolean cleanData){
		HttpClientHandler handle = new HttpClientHandler(request,this);
		HttpRequestLog requestLog = handle.execute();
		if(httpRequestLogList.size()<10){//防止分页过多，只保存接口的前10次调用日志
			requestLog.setPguid(request.getGuid());
			requestLog.setPpguid(httpSequence.getGuid());
			httpRequestLogList.add(requestLog);
		}
		/*if(StringUtils.isNotEmpty(handle.getOutput())){
			throw new ServiceException(handle.getOutput());
		}*/
		if(apiData){
			List<Map<String,Object>> dataList = getResponseData(request,requestLog,this);
			if(dataList==null||dataList.size()==0){
				return false;
			}else{
				if(cleanData){
					excuteCleanData(dockDataConfig);
				}
				for(int i =0;i<dataList.size();i++){
					list.add(dataList.get(i));
					if(list.size()>=dockDataConfig.getBatchLimit()){
						Map<String,Object> fieldMap = (Map<String,Object>)JSONObject.parse(dockDataConfig.getMappingRelation());
						insertData(dockDataConfig.getTableName(),fieldMap,list);
						list.clear();
					}
				}
			}
		}
		return true;
	}

	public void excuteMonitor(){
		List<HttpRequest> requests = httpSequence.getHttpRequest();
		for(HttpRequest request : requests){
			HttpClientHandler handle = new HttpClientHandler(request,this);
			HttpRequestLog requestLog = handle.execute();
			requestLog.setPguid(request.getGuid());
			requestLog.setPpguid(httpSequence.getGuid());
			httpRequestLogList.add(requestLog);
		}
	}

	public void excuteCleanData(DockDataConfig dockDataConfig){
		String cleanRule = dockDataConfig.getCleanRule();
		if(StringUtils.isNotEmpty(cleanRule)){
			StringBuffer stringBuffer = new StringBuffer();
			if(cleanRule.contains("$$")&&cleanRule.contains("#{")){
				cleanRule = cleanRule.replace("}","} ");
				String[] params = cleanRule.split("#\\{");
				for(String param:params){
					if(param.startsWith("$$")){
						String key = param.substring(0,param.indexOf("}"));
						String result = this.getVariables(key);
						stringBuffer.append(" '"+result+"' "+param.substring(param.indexOf("}")+1));
					}else{
						stringBuffer.append(param);
					}
				}
			}else{
				stringBuffer.append(cleanRule);
			}
			SpringUtils.getBean(DockDataMapper.class).cleanData(stringBuffer.toString());
		}

	}

	/*public void insertData(String tableName,Map<String,String> fieldMap,List<Map<String,Object>> list){
		List<String> fields = new ArrayList<>();
		List<String> fieldsKey = new ArrayList<>();
		List<Object[]> values = new ArrayList<>();
		for(Map.Entry<String,String> entry:fieldMap.entrySet()){
			String key = entry.getKey();
			String value = entry.getValue();
			if(StringUtils.isNotEmpty(value)){
				fields.add(key);
				fieldsKey.add(value);
			}
		}
		for(Map<String,Object> map:list){
			Object[] objects = new Object[fields.size()];
			int i = 0;
			for(String field:fieldsKey){
				int ii = 0;
				for(Map.Entry<String,Object> entry1:map.entrySet()){
					if(field.equals(entry1.getKey())){
						objects[i] = entry1.getValue();
						ii++;
						break;
					}
				}
				if(ii==0){
					objects[i] = null;
				}
				i++;
			}
			values.add(objects);
		}
		SpringUtils.getBean(DockDataMapper.class).insertData(tableName,fields,values);
	}*/

	public void insertData(String tableName,Map<String,Object> fieldMap,List<Map<String,Object>> list){
		List<String> fields = new ArrayList<>();
		List<FieldConfig> fieldsKey = new ArrayList<>();
		List<List<FieldConfig>> values = new ArrayList<>();
		for(Map.Entry<String,Object> entry:fieldMap.entrySet()){
			String key = entry.getKey();
			JSONObject jsonObject = (JSONObject)entry.getValue();
			FieldConfig value = jsonObject.toJavaObject(FieldConfig.class);
			if(StringUtils.isNotEmpty(value.getKey())){
				fields.add(key);
				fieldsKey.add(value);
			}
		}
		for(Map<String,Object> map:list){
			Object[] objects = new Object[fields.size()];
			List<FieldConfig> item = new ArrayList<>();
			for(FieldConfig field:fieldsKey){
				if(FieldConfig.TargetType.DYNAMIC.name().equals(field.getType())){
					for(Map.Entry<String,Object> entry1:map.entrySet()){
						if(field.getKey().equals(entry1.getKey())){
							field.setValue(entry1.getValue());
							break;
						}
					}
				}else if(FieldConfig.TargetType.STATIC.name().equals(field.getType())){
					if(StringUtils.isNotNull(field.getValue())&&String.valueOf(field.getValue()).contains("$$")){
						field.setValue(this.getVariables(String.valueOf(field.getValue())));
					}
				}

				FieldConfig fieldNew = new FieldConfig();
				BeanUtils.copyProperties(field,fieldNew);
				item.add(fieldNew);
			}
			values.add(item);
		}
		SpringUtils.getBean(DockDataMapper.class).insertData(tableName,fields,values);
	}

	public List<Map<String,Object>> getResponseData(HttpRequest request,HttpRequestLog requestLog,HttpSequenceHandle httpSequenceHandle){
		String body = requestLog.getResponseBody();
		if(StringUtils.isEmpty(body)){
			return null;
		}
		Map<String,String> variab = request.getVariablesMap();
		String key = "";
		if(variab!=null){
			for(Map.Entry<String,String> entry:variab.entrySet()){
				key = entry.getKey();
				break;
			}
		}
		String result = StringUtils.isNotEmpty(key)?httpSequenceHandle.getVariables(key):body;
		if(StringUtils.isEmpty(result)){
			return null;
		}
		List<Map<String,Object>> bodyList = null;
		if(result.startsWith("{")){
			Map<String,Object> bodyMap = (Map<String,Object>)JSONObject.parse(result);
			bodyList = new ArrayList<>();
			bodyList.add(bodyMap);
		}else if(result.startsWith("[")){
			bodyList = JSONArray.parseObject(result,List.class);
		}
		return bodyList;
	}

	public HttpRequest getWhileRequest(HttpRequest request,String whileRule){
		HashMap<String,String> param = request.getParametersMap();
		for(Map.Entry<String,String> entry:param.entrySet()){
			if(entry.getKey().equals(whileRule)){
				Integer pageNum = Integer.parseInt(entry.getValue())+1;
				param.put(entry.getKey(),String.valueOf(pageNum));
			}
		}
		request.setParametersMap(param);
		return request;
	}

	public void test(){
		List<HttpRequest> requests = httpSequence.getHttpRequest();
		for(HttpRequest request : requests){
			HttpClientHandler handle = new HttpClientHandler(request,this);
			HttpRequestLog requestLog = handle.execute();
			requestLog.setPguid(request.getGuid());
			requestLog.setPpguid(httpSequence.getGuid());
			httpRequestLogList.add(requestLog);
		}
//		handleLog();

	}
	
	private void handleLog(StringBuffer msg){
		StringBuffer tempLog = new StringBuffer();
		for(HttpRequestLog log : httpRequestLogList){
			if(StringUtil.isNotEmpty(log.getLog())){
				if(tempLog.length() != 0){
					tempLog.append("\r\n");
				}
				tempLog.append(log.getLog());
			}
		}
		httpSequenceLog.setPguid(httpSequence.getGuid());
		httpSequenceLog.setCostTime(new Date().getTime()-httpSequenceLog.getCostTime());
		if(tempLog.length()!=0){
			httpSequenceLog.setLog(tempLog.toString());
			httpSequenceLog.setStatus(StringUtil.isEmpty(tempLog.toString()));
		}else if(msg.length()!=0){
			httpSequenceLog.setLog(msg.toString());
			httpSequenceLog.setStatus(StringUtil.isEmpty(msg.toString()));
		}else{
			httpSequenceLog.setStatus(true);
		}

	}
	
	
	public void setVariables(String key, String value){
		variables.put(key, value);
	}
	
	public String getVariables(String val){
		for (String variableName : variables.keySet()) {
			if(variableName.equals(val)){
				return variables.get(variableName);
			}
		}
		return null;
	}
	
	
}
